package com.luckdraw.util;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Map;
import java.util.Map.Entry;
import java.util.SortedMap;
import java.util.TreeMap;

import org.apache.commons.lang.StringUtils;

public class SecurityUtil {
	private static final char[] DIGITS = { '0', '1', '2', '3', '4', '5', '6',
		'7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
	private static final String SHA1_ALGORITHM = "SHA1";
	private static final String MD5_ALGORITHM = "MD5";
	public static final String DEFAULT_CHARSET = "UTF-8";

	
	public static String sha1(String str) throws Exception {
		return sha1(str, null);
	}
	
	public static String sha1(String str, String charset) throws Exception {
		return encrypt(str, SHA1_ALGORITHM, charset);
	}
	
	public static String md5(String str) throws Exception {
		return md5(str, null);
	}
	
	public static String md5(String str, String charset) {
		return encrypt(str, MD5_ALGORITHM, charset);
	}
	
	/**
	 * 加密
	 * @param str	需要加密的字符串
	 * @param algorithm	算法, 为null则使用默认算法MD5
	 * @param charset 编码格式	, 为null则使用默认编码格式 UTF-8
	 * @return 指定字符串加密后的16进制字符串
	 */
	public static String encrypt (String str, String algorithm, String charset) {
		
		if (str == null)
			return null;
		
		if (algorithm == null)
			algorithm = MD5_ALGORITHM;
		
		if (charset == null)
			charset = DEFAULT_CHARSET;
		
		String encryptStr = null;
		
		try {
			MessageDigest md = MessageDigest.getInstance(algorithm);
			md.update(str.getBytes(charset));
			
			encryptStr = new String(encodeHex(md.digest()));
			
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
			System.out.println("指定的加密算法不存在");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
			System.out.println("指定了不支持的编码格式");
		}
		
		return encryptStr;
	}
	
	
	public static char[] encodeHex(byte[] data) {

		int l = data.length;

		char[] out = new char[l << 1];

		// two characters form the hex value.
		for (int i = 0, j = 0; i < l; i++) {
			out[j++] = DIGITS[(0xF0 & data[i]) >>> 4];
			out[j++] = DIGITS[0x0F & data[i]];
		}

		return out;
	}
	
	/**
     * 判断签名前后是否相同
     * @param text 需要签名的字符串
     * @param sign 签名结果
     * @param input_charset 编码格式
     * @return 签名结果
     */
    public static boolean verify(String text, String sign, String input_charset) {
    	String mysign = md5(text, input_charset);
    	if(mysign.equals(sign)) {
    		return true;
    	}
    	else {
    		return false;
    	}
    }
    
    /**
     * 判断签名前后是否相同
     * @param text 需要签名的字符串
     * @param sign 签名结果
     * @return 签名结果
     */
    public static boolean verify(String text,String sign){
    	return verify(text, sign, DEFAULT_CHARSET);
    }
    
    /**
	 * 签名算法
	 * 
	 * @param sortedMap
	 * @param md5key
	 * @return
	 */
	public static String buildSignParamStr(SortedMap<String, String> sortedMap,String md5key) {
		/*SortedMap<String, String> map = new TreeMap<String, String>();
		for (String pname : sortedMap.keySet()) {
			map.put(pname, sortedMap.get(pname));
		}
		map.put("merc_key", md5key);

		StringBuilder sb = new StringBuilder(500);
		for (String pname : map.keySet()) {
			if ("sign".equals(pname) || StringUtils.isEmpty(map.get(pname))) {
				continue;
			}
			sb.append(pname).append("=").append(map.get(pname)).append("&");
		}
		sb = sb.deleteCharAt(sb.length() - 1);*/
		return buildSignParamStr(sortedMap,md5key,"merc_key");
	}
	
	/**
	 * 
	 * @param sortedMap
	 * @param md5key
	 * @param keyName
	 * @return
	 */
	public static String buildSignParamStr(SortedMap<String, String> sortedMap,String md5key,String keyName){
		SortedMap<String, String> map = new TreeMap<String, String>(sortedMap);
		for (String pname : sortedMap.keySet()) {
			map.put(pname, sortedMap.get(pname));
		}
		map.put(keyName, md5key);

		StringBuilder sb = new StringBuilder(500);
		for (String pname : map.keySet()) {
			if ("sign".equals(pname) || StringUtils.isEmpty(map.get(pname))) {
				continue;
			}
			sb.append(pname).append("=").append(map.get(pname)).append("&");
		}
		sb = sb.deleteCharAt(sb.length() - 1);
		return sb.toString();
	}
	
	public static String buildSignParamStr(Map<String, String> sortedMap,String secret){
		SortedMap<String, String> map = new TreeMap<String, String>(sortedMap);
		StringBuffer sb = new StringBuffer();
		int index = 0;
		for(Entry<String, String> entry:map.entrySet()){
			index++;
			if("sign".equals(entry.getKey())||StringUtils.isEmpty(entry.getValue())){
				continue;
			}
			sb.append(entry.getKey()).append("=").append(entry.getValue());
			if(index<map.entrySet().size()){
				sb.append("&");
			}
		}
		sb.append(secret);
		return sb.toString();
	}
	
	public static String buildSignParamStr(Map<String, String> params){
		SortedMap<String, String> map = new TreeMap<String, String>();
		for (String pname : params.keySet()) {
			map.put(pname, params.get(pname));
		}
		StringBuilder sb = new StringBuilder(500);
		for (String pname : map.keySet()) {
			if ("sign".equals(pname) || StringUtils.isEmpty(map.get(pname))) {
				continue;
			}
			sb.append(pname).append("=").append(map.get(pname)).append("&");
		}
		sb = sb.deleteCharAt(sb.length() - 1);
		return sb.toString();
	}
    
    public static void main(String[] args) {
		Map<String, String> sortMap = new TreeMap<String, String>();
		sortMap.put("payStatus", "ORDER_FINISHED");
		sortMap.put("orderId", "14292");
		sortMap.put("traddeNum", "161223500000002277");
		String sign = SecurityUtil.md5(SecurityUtil.buildSignParamStr(sortMap, "589a10e0efebc397a8715f0fc83b9fb3"), "utf-8");
		System.out.println(sign);
	}
}
